package net.wanglu.www.zzz.rule.sva;

import java.util.HashMap;
import java.util.regex.Pattern;

import net.wanglu.www.zzz.rule.BadEgg;
import net.wanglu.www.zzz.rule.Rule;
import net.wanglu.www.zzz.service.se.expl._ExplTuple;
import net.wanglu.www.zzz.service.se.nsubj._NSubjTuple;
import edu.stanford.nlp.ling.TaggedWord;
import edu.stanford.nlp.trees.Tree;
import edu.stanford.nlp.trees.TreeGraphNode;
import edu.stanford.nlp.trees.tregex.TregexPattern;

public class Each_Every_ManyA_MoreThan_No_OneAndAHalfAsSubj extends _SvaRule {

	public static final TregexPattern Each0 = TregexPattern.compile("/\\bNP\\b/<(/\\bDT\\b/</\\bEach\\b/)<(/\\bNN\\b/</\\w+/)");
	public static final TregexPattern Each1 = TregexPattern.compile("/\\bNP\\b/<(/\\bNP\\b/<(/\\bDT\\b/</\\bEach\\b/)<(/\\bNN\\b/</\\w+/))<(/\\bCC\\b/</\\band\\b/)<(/\\bNP\\b/<(/\\bDT\\b/</\\bEach\\b/)<(/\\bNN\\b/</\\w+/))");
	public static final TregexPattern Each2 = TregexPattern.compile("/\\bNP\\b/<(/\\bNP\\b/<(/\\bDT\\b/</\\bEach\\b/)<(/\\bNN\\b/</\\w+/))<(/\\bCC\\b/</\\band\\b/)<(/\\bNN\\b/</\\w+/)");
	public static final TregexPattern Every0 = TregexPattern.compile("/\\bNP\\b/<(/\\bDT\\b/</\\bEvery\\b/)<(/\\bNN\\b/</\\w+/)");
	public static final TregexPattern Every1 = TregexPattern.compile("/\\bNP\\b/<(/\\bDT\\b/</\\bEvery\\b/)<(/\\bJJ\\b/</\\w+/)<(/\\bNN\\b/</\\w+/)");
	public static final TregexPattern Every2 = TregexPattern.compile("/\\bNP\\b/<(/\\bNP\\b/<(/\\bDT\\b/</\\bEvery\\b/)<(/\\bNN\\b/</\\w+/))<(/\\bCC\\b/</\\band\\b/)<(/\\bNP\\b/<(/\\bDT\\b/</\\bevery\\b/)<(/\\bNN\\b/</\\w+/))");
	public static final TregexPattern Every3 = TregexPattern.compile("/\\bNP\\b/<(/\\bNP\\b/<(/\\bDT\\b/</\\bEvery\\b/)<(/\\bJJ\\b/</\\w+/)<(/\\bNN\\b/</\\w+/))<(/\\bCC\\b/</\\band\\b/)<(/\\bNP\\b/<(/\\bDT\\b/</\\bevery\\b/)<(/\\bJJ\\b/</\\w+/)<(/\\bNN\\b/</\\w+/))");
	public static final TregexPattern ManyA0 = TregexPattern.compile("/\\bNP\\b/<(/\\bPDT\\b/</\\bMany\\b/)<(/\\bDT\\b/</\\ba\\b/)<(/\\bNN\\b/</\\w+/)");
	public static final TregexPattern ManyA1 = TregexPattern.compile("/\\bNP\\b/<(/\\bPDT\\b/</\\bMany\\b/)<(/\\bDT\\b/</\\ba\\b/)<(/\\bJJ\\b/</\\w+/)<(/\\bNN\\b/</\\w+/)");
	public static final TregexPattern ManyA2 = TregexPattern.compile("/\\bNP\\b/<(/\\bNP\\b/<(/\\bPDT\\b/</\\bMany\\b/)<(/\\bDT\\b/</\\ba\\b/)<(/\\bNN\\b/</\\w+/))<(/\\bCC\\b/</\\band\\b/)<(/\\bNP\\b/<(/\\bPDT\\b/</\\bmany\\b/)<(/\\bDT\\b/</\\ba\\b/)<(/\\bNN\\b/</\\w+/))");
	public static final TregexPattern ManyA3 = TregexPattern.compile("/\\bNP\\b/<(/\\bNP\\b/<(/\\bPDT\\b/</\\bMany\\b/)<(/\\bDT\\b/</\\ba\\b/)<(/\\bJJ\\b/</\\w+/)<(/\\bNN\\b/</\\w+/))<(/\\bCC\\b/</\\band\\b/)<(/\\bNP\\b/<(/\\bPDT\\b/</\\bmany\\b/)<(/\\bDT\\b/</\\ba\\b/)<(/\\bJJ\\b/</\\w+/)<(/\\bNN\\b/</\\w+/))");
	public static final TregexPattern MoreThanOneNN = TregexPattern.compile("/\\bNP\\b/<(/\\bQP\\b/<(/\\bJJR\\b/</\\bMore\\b/)<(/\\bIN\\b/</\\bthan\\b/)<(/\\bCD\\b/</\\bone\\b/)<(/\\bNN\\b/))");
	public static final TregexPattern MoreThanCDNNS = TregexPattern.compile("/\\bNP\\b/<(/\\bQP\\b/<(/\\bJJR\\b/</\\bMore\\b/)<(/\\bIN\\b/</\\bthan\\b/)</\\bCD\\b/</\\bCD\\b/)");
	public static final TregexPattern MoreNNSThanOne = TregexPattern.compile("/\\bNP\\b/<(/\\bNP\\b/<(/\\bJJR\\b/</\\bMore\\b/)<(/\\bNNS\\b/))<(/\\bPP\\b/<(/\\bIN\\b/</\\bthan\\b/)<(/\\bCD\\b/</\\bone\\b/))");
	public static final TregexPattern MoreThanOne = TregexPattern.compile("/\\bNP\\b/<(/\\bQP\\b/<(/\\bJJR\\b/</\\bMore\\b/)<(/\\bIN\\b/</\\bthan\\b/)<(/\\bCD\\b/</\\bone\\b/))");
	public static final Pattern OneAndAHalf = Pattern.compile("\\bOne and a half\\b");
	public static final Pattern AAndAHalf = Pattern.compile("\\bA\\b.*?\\band a half\\b");

	public final int EachFlag = 1;
	public final int EveryFlag = 2;
	public final int ManyAFlag = 3;
	public final int MoreThanOneNNFlag = 4;
	public final int MoreThanCDNNSFlag = 5;
	public final int MoreNNSThanOneFlag = 6;
	public final int MoreThanOneFlag = 7;
	public final int AndAHalfFlag = 8;

	@Override
	public Object applicable(Object... objects) throws Exception {
		// TODO Auto-generated method stub
		if ( super.applicable(objects) == Rule.Inapplicable) return Rule.Inapplicable;
		_NSubjTuple nst = (_NSubjTuple) objects[1];
		if ( !"NP".equals(nst.getSubjectAncestor().value())) return Rule.Inapplicable;
		return Rule.Applicable;
	}

	@Override
	public Object deviseRightSolution(Object... objects) throws Exception {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object examine(Object... objects) throws Exception {
		// TODO Auto-generated method stub
		HashMap<?, ?> preprocessData = (HashMap<?, ?>) objects[0];
		_NSubjTuple nst =  (_NSubjTuple) objects[1];
		
		if ( this.applicable(preprocessData, nst) == Rule.Inapplicable) return Rule.Inapplicable;
		TreeGraphNode subj = (TreeGraphNode) nst.getSubj();
		TreeGraphNode verb = (TreeGraphNode) nst.getVerb();
		TreeGraphNode cop = (TreeGraphNode) nst.getCop();
		TreeGraphNode closestAux = (TreeGraphNode) nst.getAux();
		Tree subjAncestor = nst.getSubjectAncestor();
		
		TreeGraphNode pred = verb;
		if ( cop != null) pred = cop;
		if ( closestAux != null) pred = closestAux;
		String predWord = pred.label().word();
		String predTag = pred.label().tag();

		sb.clear();
		for( TaggedWord tw : subjAncestor.taggedYield()) {
			sb.append(tw.word()).append(" ");
		}
		
		if ( Each_Every_ManyA_MoreThan_No_OneAndAHalfAsSubj.Each2.matcher(subjAncestor).find()) {
			if (Rule.SingularVerb.matcher(predTag).find() && !"were".equals(predWord)) {
				return null;
			} else {
				BadEgg egg = new BadEgg();
				egg.setFlag(this.EachFlag);
				egg.setProperty(BadEgg.Error);
				egg.setViolatedRule(this);
				egg.whereIsWrong = nst;
				return egg;
			}			
		} else if ( Each_Every_ManyA_MoreThan_No_OneAndAHalfAsSubj.Each1.matcher(subjAncestor).find()) {
			if (Rule.SingularVerb.matcher(predTag).find() && !"were".equals(predWord)) {
				return null;
			} else {
				BadEgg egg = new BadEgg();
				egg.setFlag(this.EachFlag);
				egg.setProperty(BadEgg.Error);
				egg.setViolatedRule(this);
				egg.whereIsWrong = nst;
				return egg;
			}						
		} else if ( Each_Every_ManyA_MoreThan_No_OneAndAHalfAsSubj.Each0.matcher(subjAncestor).find()) {
			if (Rule.PluralVerb.matcher(predTag).find() && !"was".equals(predWord)) {
				return null;
			} else {
				BadEgg egg = new BadEgg();
				egg.setFlag(this.EachFlag);
				egg.setProperty(BadEgg.Error);
				egg.setViolatedRule(this);
				egg.whereIsWrong = nst;
				return egg;
			}											
		} else if ( Each_Every_ManyA_MoreThan_No_OneAndAHalfAsSubj.Every3.matcher(subjAncestor).find()) {
			if (Rule.SingularVerb.matcher(predTag).find() && !"were".equals(predWord)) {
				return null;
			} else {
				BadEgg egg = new BadEgg();
				egg.setFlag(this.EveryFlag);
				egg.setProperty(BadEgg.Error);
				egg.setViolatedRule(this);
				egg.whereIsWrong = nst;
				return egg;
			}						
		} else if ( Each_Every_ManyA_MoreThan_No_OneAndAHalfAsSubj.Every2.matcher(subjAncestor).find()) {
			if (Rule.SingularVerb.matcher(predTag).find() && !"were".equals(predWord)) {
				return null;
			} else {
				BadEgg egg = new BadEgg();
				egg.setFlag(this.EveryFlag);
				egg.setProperty(BadEgg.Error);
				egg.setViolatedRule(this);
				egg.whereIsWrong = nst;
				return egg;
			}						
		} else if ( Each_Every_ManyA_MoreThan_No_OneAndAHalfAsSubj.Every1.matcher(subjAncestor).find()) {
			if (Rule.SingularVerb.matcher(predTag).find() && !"were".equals(predWord)) {
				return null;
			} else {
				BadEgg egg = new BadEgg();
				egg.setFlag(this.EveryFlag);
				egg.setProperty(BadEgg.Error);
				egg.setViolatedRule(this);
				egg.whereIsWrong = nst;
				return egg;
			}						
		} else if ( Each_Every_ManyA_MoreThan_No_OneAndAHalfAsSubj.Every0.matcher(subjAncestor).find()) {
			if (Rule.SingularVerb.matcher(predTag).find() && !"were".equals(predWord)) {
				return null;
			} else {
				BadEgg egg = new BadEgg();
				egg.setFlag(this.EveryFlag);
				egg.setProperty(BadEgg.Error);
				egg.setViolatedRule(this);
				egg.whereIsWrong = nst;
				return egg;
			}						
		} else if ( Each_Every_ManyA_MoreThan_No_OneAndAHalfAsSubj.ManyA3.matcher(subjAncestor).find()) {
			if (Rule.SingularVerb.matcher(predTag).find() && !"were".equals(predWord)) {
				return null;
			} else {
				BadEgg egg = new BadEgg();
				egg.setFlag(this.ManyAFlag);
				egg.setProperty(BadEgg.Error);
				egg.setViolatedRule(this);
				egg.whereIsWrong = nst;
				return egg;
			}						
		} else if ( Each_Every_ManyA_MoreThan_No_OneAndAHalfAsSubj.ManyA2.matcher(subjAncestor).find()) {
			if (Rule.SingularVerb.matcher(predTag).find() && !"were".equals(predWord)) {
				return null;
			} else {
				BadEgg egg = new BadEgg();
				egg.setFlag(this.ManyAFlag);
				egg.setProperty(BadEgg.Error);
				egg.setViolatedRule(this);
				egg.whereIsWrong = nst;
				return egg;
			}						
		} else if ( Each_Every_ManyA_MoreThan_No_OneAndAHalfAsSubj.ManyA1.matcher(subjAncestor).find()) {
			if (Rule.SingularVerb.matcher(predTag).find() && !"were".equals(predWord)) {
				return null;
			} else {
				BadEgg egg = new BadEgg();
				egg.setFlag(this.ManyAFlag);
				egg.setProperty(BadEgg.Error);
				egg.setViolatedRule(this);
				egg.whereIsWrong = nst;
				return egg;
			}						
		} else if ( Each_Every_ManyA_MoreThan_No_OneAndAHalfAsSubj.ManyA0.matcher(subjAncestor).find()) {
			
			if (Rule.SingularVerb.matcher(predTag).find() && !"were".equals(predWord)) {
				return null;
			} else {
				BadEgg egg = new BadEgg();
				egg.setFlag(this.ManyAFlag);
				egg.setProperty(BadEgg.Error);
				egg.setViolatedRule(this);
				egg.whereIsWrong = nst;
				return egg;
			}						
		} else if ( Each_Every_ManyA_MoreThan_No_OneAndAHalfAsSubj.MoreThanOneNN.matcher(subjAncestor).find()) {
			Object obj = nst.customize();
			if ( obj != null && obj instanceof _ExplTuple) {
				BadEgg egg = new BadEgg();
				egg.setFlag(this.MoreThanOneNNFlag);
				egg.setProperty(BadEgg.Warning);
				egg.setViolatedRule(this);
				egg.whereIsWrong = nst;
				return egg;				
			} else {
				if (Rule.SingularVerb.matcher(predTag).find() && !"were".equals(predWord)) {
					return null;
				} else {
					BadEgg egg = new BadEgg();
					egg.setFlag(this.MoreThanOneNNFlag);
					egg.setProperty(BadEgg.Error);
					egg.setViolatedRule(this);
					egg.whereIsWrong = nst;
					return egg;
				}				
			}
		} else if ( Each_Every_ManyA_MoreThan_No_OneAndAHalfAsSubj.MoreThanCDNNS.matcher(subjAncestor).find()) {
			if (Rule.PluralVerb.matcher(predTag).find() && !"was".equals(predWord)) {
				return null;
			} else {
				BadEgg egg = new BadEgg();
				egg.setFlag(this.MoreThanCDNNSFlag);
				egg.setProperty(BadEgg.Error);
				egg.setViolatedRule(this);
				egg.whereIsWrong = nst;
				return egg;
			}
		} else if ( Each_Every_ManyA_MoreThan_No_OneAndAHalfAsSubj.MoreNNSThanOne.matcher(subjAncestor).find()) {
			if (Rule.PluralVerb.matcher(predTag).find() && !"was".equals(predWord)) {
				return null;
			} else {
				BadEgg egg = new BadEgg();
				egg.setFlag(this.MoreNNSThanOneFlag);
				egg.setProperty(BadEgg.Error);
				egg.setViolatedRule(this);
				egg.whereIsWrong = nst;
				return egg;
			}
		} else if ( Each_Every_ManyA_MoreThan_No_OneAndAHalfAsSubj.MoreThanOne.matcher(subjAncestor).find()) {
			BadEgg egg = new BadEgg();
			egg.setFlag(this.MoreThanOneFlag);
			egg.setProperty(BadEgg.Warning);
			egg.setViolatedRule(this);
			egg.whereIsWrong = nst;
			return egg;
		} else if ( Each_Every_ManyA_MoreThan_No_OneAndAHalfAsSubj.OneAndAHalf.matcher(sb.toString().trim()).find()) {
			BadEgg egg = new BadEgg();
			egg.setFlag(this.AndAHalfFlag);
			egg.setProperty(BadEgg.Warning);
			egg.setViolatedRule(this);
			egg.whereIsWrong = nst;
			return egg;
		} else if ( Each_Every_ManyA_MoreThan_No_OneAndAHalfAsSubj.AAndAHalf.matcher(sb.toString().trim()).find()) {
			BadEgg egg = new BadEgg();
			egg.setFlag(this.AndAHalfFlag);
			egg.setProperty(BadEgg.Warning);
			egg.setViolatedRule(this);
			egg.whereIsWrong = nst;
			return egg;
		}
		return Rule.Inapplicable;
	}
	@Override
	public Object whyItsWrong(Object... objects) throws Exception {
		// TODO Auto-generated method stub
		BadEgg egg = (BadEgg) objects[0];
		sb.clear();
		switch(egg.getFlag()){
		case EachFlag:
			sb.append("<p>");
			sb.append("each作主语时具有分配作用，它所修饰的名词一定是单数，谓语动词也要采用单数形式。");
			sb.append("Each boy gets a prize.");
			sb.append("<br>");
			sb.append("Each senator and congressman was allocated two seats.");
			sb.append("<br>");
			sb.append("Each boy and each girl wants to serve the people in the future.");
			sb.append("</p>");
			break;
		case EveryFlag:
			sb.append("<p>");
			sb.append("every具有分配作用，用作主语时，后接单数名词，谓语动词采用单数形式。例如：");
			sb.append("<br>");
			sb.append("Every good teacher studies his subject carefully.");
			sb.append("<br>");
			sb.append("Every adult and every child was holding a flag.");
			sb.append("</p>");
			break;
		case ManyAFlag:
			sb.append("<p>");
			sb.append("many a + 单数名词的结构意为很多的，但其后的谓语动词要用单数形式。");
			sb.append("<br>");
			sb.append("Many a boy has lost his heart to Louise.");
			sb.append("<br>");
			sb.append("Many a worker and many a peasant has praised the play.");
			sb.append("<br>");
			sb.append("Many a rough man has been civilized by his wife.");
			sb.append("</p>");
			break;
		case MoreThanOneNNFlag:
			sb.append("<p>");
			sb.append("在more than one+单数名词作主语时，谓语动词用单数，但在there be结构中，谓语动词单复数都可以。");
			sb.append("<br>");
			sb.append("More than one house was burnt down in the great fire.");
			sb.append("<br>");
			sb.append("More than one recent writer has drawn a comparison between Lord Nuffield and Caunegie.");
			sb.append("<br>");
			sb.append("There are more than one student in the bedroom now.");
			sb.append("</p>");
			break;
		case MoreThanCDNNSFlag:
			sb.append("<p>");
			sb.append("在more than+数词+复数名词作主语时，谓语动词用复数。");
			sb.append("<br>");
			sb.append("More than one thousand men and women are working in this factory.");
			sb.append("<br>");
			sb.append("More than two hundred people have turned out for the procession.");
			sb.append("</p>");
			break;
		case MoreNNSThanOneFlag:
			sb.append("<p>");
			sb.append("在more+复数名词+than one作主语时，谓语动词用复数。");
			sb.append("<br>");
			sb.append("More persons than one have been executed by the firing squads.");
			sb.append("<br>");
			sb.append("More teachers than one have been transferred.");
			sb.append("</p>");
			break;
		case MoreThanOneFlag:
			sb.append("<p>");
			sb.append("more than one单独作主语时，谓语动词既可以是单数也可以是复数。");
			sb.append("<br>");
			sb.append("More than one are interested in it.");
			sb.append("<br>");
			sb.append("More than one is interested in it.");
			sb.append("</p>");
			break;
		case AndAHalfFlag:
			sb.append("<p>");
			sb.append("one and a half+复数名词或a+复数名词 and a half结构作主语，依据概念一致原则，谓语动词既可以用单数也可以用复数形式。");
			sb.append("<br>");
			sb.append("One and a half years have passed since we last met.");
			sb.append("<br>");
			sb.append("One and a half apples is left on the plate.");
			sb.append("</p>");
			break;
		default:
			return null;
		}
		return sb.toString();
	}
}
